package com.medium.house.utils.encrypt;

import com.medium.house.constant.Constant;
import com.medium.house.utils.Base64Util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
 
public class AESUtil {
  public static final AESUtil instance = new AESUtil();
 
  public static boolean initialized = false;
 
  /**
   * AES解密
   * @param content 密文
   * @return
   * @throws InvalidAlgorithmParameterException
   * @throws NoSuchProviderException
   */
  public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
    initialize();
    try {
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
      Key sKeySpec = new SecretKeySpec(keyByte, "AES");
 
      cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
      byte[] result = cipher.doFinal(content);
      return result;
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (NoSuchPaddingException e) {
      e.printStackTrace();
    } catch (InvalidKeyException e) {
      e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
      e.printStackTrace();
    } catch (BadPaddingException e) {
      e.printStackTrace();
    } catch (NoSuchProviderException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  }
 
  public static void initialize(){
    if (initialized) {return;}
    Security.addProvider(new BouncyCastleProvider());
    initialized = true;
  }
  //生成iv
  public static AlgorithmParameters generateIV(byte[] iv) throws Exception{
    AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
    params.init(new IvParameterSpec(iv));
    return params;
  }

  private static String AES_ALGORITHM = "AES/ECB/PKCS5Padding";

  private static String CHAR_ENCODING = "UTF-8";

  /**
   * 加密
   *
   * @param data 需要加密的内容
   * @param key 加密密码
   * @return
   */
  public static byte[] encrypt(byte[] data, byte[] key) {
    if (key.length != 16) {
      throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
    }
    try {
      SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
      byte[] enCodeFormat = secretKey.getEncoded();
      SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
      Cipher cipher = Cipher.getInstance(AES_ALGORITHM);// 创建密码器
      cipher.init(Cipher.ENCRYPT_MODE, seckey);// 初始化
      byte[] result = cipher.doFinal(data);
      return result; // 加密
    } catch (Exception e) {
      throw new RuntimeException("encrypt fail!", e);
    }
  }

  /**
   * 解密
   *
   * @param data 待解密内容
   * @param key 解密密钥
   * @return
   */
  public static byte[] decrypt(byte[] data, byte[] key) {
    if (key.length != 16) {
      throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
    }
    try {
      SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
      byte[] enCodeFormat = secretKey.getEncoded();
      SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");
      Cipher cipher = Cipher.getInstance(AES_ALGORITHM);// 创建密码器
      cipher.init(Cipher.DECRYPT_MODE, seckey);// 初始化
      byte[] result = cipher.doFinal(data);
      return result; // 加密
    } catch (Exception e) {
      throw new RuntimeException("decrypt fail!", e);
    }
  }

  /**
   * 加密
   *
   * @param data 需要加密的内容
   * @param key 加密密码
   * @return Base64编码的字符串
   */
  public static String encryptToBase64(String data, String key) {
    try {
      byte[] valueByte = encrypt(data.getBytes(CHAR_ENCODING), key.getBytes(CHAR_ENCODING));
      return new String(Base64Util.encode(valueByte));
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("encrypt fail!", e);
    }

  }

  /**
   * 解密
   *
   * @param data 待解密内容 Base64编码的字符串
   * @param key 解密密钥
   * @return
   */
  public static String decryptFromBase64(String data, String key) {
    try {
      byte[] originalData = Base64Util.decode(data.getBytes());
      byte[] valueByte = decrypt(originalData, key.getBytes(CHAR_ENCODING));
      return new String(valueByte, CHAR_ENCODING);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("decrypt fail!", e);
    }
  }

  /**
   * 加密
   *
   * @param data 需要加密的内容
   * @param key 加密密码 Base64编码的字符串
   * @return Base64编码的字符串
   */
  public static String encryptWithKeyBase64(String data, String key) {
    try {
      byte[] valueByte = encrypt(data.getBytes(CHAR_ENCODING), Base64Util.decode(key.getBytes()));
      return new String(Base64Util.encode(valueByte));
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("encrypt fail!", e);
    }
  }

  /**
   * 解密
   *
   * @param data 待解密内容 Base64编码的字符串
   * @param key 解密密钥 Base64编码的字符串
   * @return
   */
  public static String decryptWithKeyBase64(String data, String key) {
    try {
      byte[] originalData = Base64Util.decode(data.getBytes());
      byte[] valueByte = decrypt(originalData, Base64Util.decode(key.getBytes()));
      return new String(valueByte, CHAR_ENCODING);
    } catch (UnsupportedEncodingException e) {
      throw new RuntimeException("decrypt fail!", e);
    }
  }

  public static void main(String[] args) {
    String name=AESUtil.encryptToBase64("曹杰", Constant.AES_KEY);
    System.out.println(name);
    String name2=AESUtil.decryptFromBase64(name, Constant.AES_KEY);
    System.out.println(name2);
  }
}